﻿#include <glog/logging.h>
#include <QFile>

#include "util/utils.h"
#include "entity/mqtt_entity.h"
#include "manager/config_manager.h"
#include "manager/mqtt_manager.h"
#include "manager/json_parser.h"
#include "mqtt/mqtt_client_config.h"
#include "mqtt/mqtt_client_command.h"
#include "mqtt/mqtt_client_status.h"
#include "mqtt/mqtt_client_human.h"
#include "mqtt/mqtt_client_result.h"
#include "mqtt/mqtt_client_picture.h"
#include "mqtt/mqtt_client_video.h"
#include "mqtt/mqtt_client_update.h"
#include "mqtt/mqtt_client_calibrate.h"
#include "mqtt/mqtt_client_update_result.h"

MqttManager::MqttManager()
{
    mosqpp::lib_init();

    const char *pClientId = Utils::get_client_id().toLatin1().data();
    memset(clientId, 0, sizeof(clientId));
    memcpy(clientId, pClientId, strlen(pClientId));
    LOG(INFO) << "MqttManager | clientId" << clientId;
}

MqttManager::~MqttManager() {
    mosqpp::lib_cleanup();
}

MqttManager *MqttManager::getInstance() {
    static MqttManager instance;
    return &instance;
}

bool MqttManager::init() {
    AppConfig *app_config = ConfigManager::getInstance()->get_app_config();
    int port = app_config->port;
    const char *broker = app_config->broker.toLatin1().data();
    char hostname[MAX_HOSTNAME_SIZE];
    memset(hostname, 0, sizeof(hostname));
    memcpy(hostname, broker, strlen(broker));

    for (int i = 0; i < TOPIC_SIZE; ++i) {
        MqttClient *client = NULL;
        MqttClientThread *thread = NULL; 
        QString str_client_id = QString("%1-%2").arg(clientId).arg(i);
        switch (i) {
            case CONFIG_TOPIC_INDEX:
                client = new MqttClientConfig(str_client_id.toLatin1().data(), TOPIC_CONFIG, hostname, port);
                thread = new MqttClientThread(client);
                break;
            case COMMAND_TOPIC_INDEX:
                client = new MqttClientCommand(str_client_id.toLatin1().data(), TOPIC_COMMAND, hostname, port);
                thread = new MqttClientThread(client);
                break;
            case STATUS_TOPIC_INDEX:
                client = new MqttClientStatus(str_client_id.toLatin1().data(), TOPIC_STATUS, hostname, port);
                thread = new MqttClientThread(client);
                break;
            case RESULT_TOPIC_INDEX:
                client = new MqttClientResult(str_client_id.toLatin1().data(), TOPIC_RESULT, hostname, port);
                thread = new MqttClientThread(client);
                break;
            case PICTURE_TOPIC_INDEX:
                client = new MqttClientPicture(str_client_id.toLatin1().data(), TOPIC_PICTURE, hostname, port);
                thread = new MqttClientThread(client);
                break;
            case VIDEO_TOPIC_INDEX:
                client = new MqttClientVideo(str_client_id.toLatin1().data(), TOPIC_VIDEO, hostname, port);
                thread = new MqttClientThread(client);
                break;
             case UPDATE_TOPIC_INDEX:
                client = new MqttClientUpdate(str_client_id.toLatin1().data(), TOPIC_UPDATE, hostname, port);
                thread = new MqttClientThread(client);
                break;
            case UPDATE_RESULT_TOPIC_INDEX:
                client = new MqttClientUpdateResult(str_client_id.toLatin1().data(), TOPIC_UPDATE_RESULT, hostname, port);
                thread = new MqttClientThread(client);
                break;
            case HUMAN_TOPIC_INDEX:
                client = new MqttClientHuman(str_client_id.toLatin1().data(), TOPIC_HUMAN, hostname, port);
                thread = new MqttClientThread(client);
                break;
            case CAMERA_CALIBRATION:
                client = new MqttClientCalibrate(str_client_id.toLatin1().data(), TOPIC_CALIBRATION, hostname, port);
                thread = new MqttClientThread(client);
                break;
            default:
                break;
        }
        mqtt_clients[i] = client;
        mqtt_threads[i] = thread;
    }
    for (int i = 0; i < TOPIC_SIZE; ++i) {
        mqtt_threads[i]->start();
        QThread::msleep(200);
    }
    return true;
}

 bool MqttManager::send_status(StatusEntity *status) {
    status->version = VERSION_NAME;
    MqttClientStatus *client = (MqttClientStatus*)mqtt_clients[STATUS_TOPIC_INDEX];
    QString str_payload = JsonParser::json_status(*status);
    char *payload = Utils::str_to_char_array(str_payload);
    int len = str_payload.toLatin1().length();
    LOG(INFO) << "MqttManager | send_status | payload" << payload << ", len" << len;
    client->publish_topic(payload, len, true);
    delete []payload;
    return true;
 }

 bool MqttManager::send_pedestrian(std::vector<AlgorithmResultEntity> *v_pedestrian) {
    MqttClientHuman *client = (MqttClientHuman*)mqtt_clients[HUMAN_TOPIC_INDEX];
    QString str_payload = JsonParser::json_pedestrian(v_pedestrian);
    char *payload = Utils::str_to_char_array(str_payload);
    int len = str_payload.toLatin1().length();
    LOG(INFO) << "MqttManager | send_pedestrian | payload" << payload << ", len" << len;
    client->publish_topic(payload, len, true);
    delete []payload;
    return true;
 }

 bool MqttManager::send_result(ResultEntity *result) {
     MqttClientResult *client = (MqttClientResult*)mqtt_clients[RESULT_TOPIC_INDEX];
     QString str_payload = JsonParser::json_result(*result);
     char *payload = Utils::str_to_char_array(str_payload);
     int len = str_payload.toLatin1().length();
     LOG(INFO) << "MqttManager | send_result | payload" << payload << ", len" << len;
     client->publish_topic(payload, len);
     delete []payload;
     return true;
 }

 bool MqttManager::send_picture(void *data, int len) {
    LOG(INFO) << "MqttManager | send_picture | len" << len;
    MqttClientPicture *client = (MqttClientPicture*)mqtt_clients[PICTURE_TOPIC_INDEX];
    client->publish_topic(data, len);
    return true;
 }

 bool MqttManager::send_video(void *data, long len) {
     LOG(INFO) << "MqttManager | send_video | len" << len;
     MqttClientVideo *client = (MqttClientVideo*)mqtt_clients[VIDEO_TOPIC_INDEX];
     client->publish_topic(data, len);
     return true;
 }

 bool MqttManager::send_video_file() {
     LOG(INFO) << "MqttManager | send_video_file";
     QFile file(VIDEO_FILE);
     if (!file.open(QIODevice::ReadOnly)) {
        LOG(INFO) << "MqttManager | send_video_file failed, can't open file";
        return false;
     }
     QByteArray fileArray = file.readAll();
     send_video(fileArray.data(), fileArray.size());
     return true;
 }

 bool MqttManager::send_update_result(QString result) {
     LOG(INFO) << "MqttManager | send_update_result | result" << result.toStdString();
     MqttClientUpdateResult *client = (MqttClientUpdateResult*)mqtt_clients[UPDATE_RESULT_TOPIC_INDEX];
     int len = result.toLatin1().length();
     char *payload = Utils::str_to_char_array(result);
     client->publish_topic(payload, len);
     delete []payload;
     return true;
 }
